package zhongbo.java.air.monitor.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import zhongbo.java.air.common.exception.MyException;
import zhongbo.java.air.common.vo.PageVo;
import zhongbo.java.air.monitor.Util.JtsUtil;
import zhongbo.java.air.monitor.mapper.AirAlertLogMapper;
import zhongbo.java.air.monitor.model.AirAlertLog;
import zhongbo.java.air.monitor.model.PointDto;
import zhongbo.java.air.monitor.service.IJtsService;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 说明：
 *
 * @author 钟波dellNotebook
 * @since 2025年04月09日 星期三 06:40:59
 */
@Service
@Slf4j
public class JtsServiceImpl implements IJtsService {
    @Autowired
    private AirAlertLogMapper airAlertLogMapper;

    /*
    多边形至少4个点数据, 第一个数据和最后一个数据一致, 表示点位闭合
    比如三角形最少3个点, 再加一个结束闭合点, 一共需要4个点;
         首点    一点  二点   末尾点(与首点重合)
    如: [[0,0],[0,1],[1,1],[0,0]]
    多边形示例:
    [
        {"longitude":115.95,"latitude":40.45},
        {"longitude":115.95,"latitude":39.48},
        {"longitude":117.2,"latitude":39.41},
        {"longitude":117.49,"latitude":40.41},
        {"longitude":115.95,"latitude":40.45}
    ]
     */
    @Override
    public List<PointDto> parseAlertZoneVertices(String vertices) {
        // Coordinate coordinate = new Coordinate()
        // 将字符串解析为JSONArray对象
        JSONArray jsonArray = JSONUtil.parseArray(vertices);
        // 将JSONArray对象转换为PointDto类型的List
        List<PointDto> pointList = jsonArray.toList(PointDto.class);
        // 验证点位列表是否有效
        if (!validAreaPointList(pointList)) {
            return null;
        }
        return pointList;
    }

    private boolean validAreaPointList(List<PointDto> pointList) {
        if (pointList == null) {
            log.error("校验失败! 多边形点位数据为 null");
            return false;
        }
        if (pointList.size() < 4) {
            log.error("校验失败! 多边形点位数据数量错误: {}", pointList);
            return false;
        }
        PointDto firstPoint = pointList.get(0);
        PointDto lastPoint = pointList.get(pointList.size() - 1);
        if (!firstPoint.equals(lastPoint)) {
            log.error("校验失败! 多边形点位数据数量错误: {}", pointList);
            return false;
        }
        return true;
    }

    @Override
    public boolean isInAlertZone(List<PointDto> pointList, Double longitude, Double latitude) {
        if (!validAreaPointList(pointList)) {
            throw new RuntimeException("无效的区域多边形");
        }
        Polygon polygon = convertToPolygon(pointList);
        Point point = JtsUtil.createPoint(longitude, latitude);
        return JtsUtil.isPointInPolygon(point, polygon);
    }

    /**
     * 转换为多边形对象
     *
     * @param pointList 多边形数据列表
     * @return Polygon
     */
    private Polygon convertToPolygon(List<PointDto> pointList) {
        List<Coordinate> collect = pointList.stream().map(e -> {
            Double longitude = e.getLongitude();
            Double latitude = e.getLatitude();
            return JtsUtil.createCoordinate(longitude, latitude);
        }).collect(Collectors.toList());

        Coordinate[] coordinates = ArrayUtil.toArray(collect, Coordinate.class);

        return JtsUtil.createPolygon(coordinates);
    }

    @Override
    public AirAlertLog addAirAlertLog(AirAlertLog airAlertLog) throws MyException {
        int ok = airAlertLogMapper.insert(airAlertLog);
        if (ok <=0) {
            throw new MyException("添加失败");
        }
        return airAlertLogMapper.getAirAlertLogByIcao(airAlertLog.getIcaoCode());
    }

    @Override
    public void deleteAirAlertLog(String icao) throws MyException {
        QueryWrapper<AirAlertLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("icao_code",icao);
        int ok = airAlertLogMapper.delete(queryWrapper);
        if (ok <=0) {
            throw new MyException("删除失败");
        }
    }

    @Override
    public AirAlertLog updateAirAlertLog(AirAlertLog airAlertLog) throws MyException {
int ok = airAlertLogMapper.updateById(airAlertLog);
        if (ok <=0) {
            throw new MyException("更新失败");
        }
        return airAlertLogMapper.selectById(airAlertLog.getId());
    }

    @Override
    public AirAlertLog selectAirAlertLog(String Id) throws MyException {
        AirAlertLog airAlertLog = airAlertLogMapper.selectById(Id);
        if(airAlertLog == null) {
            throw new MyException("查询失败");
        }
        return airAlertLog;
    }

    @Override
    public PageVo<AirAlertLog> page(Integer pageNumber, Integer pageSize, boolean order, String searchField, String keyword, String sortField) {
        QueryWrapper<AirAlertLog> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(keyword) && StrUtil.isNotBlank(searchField)) {
            queryWrapper.like(searchField, keyword);
        }
        if (StrUtil.isNotBlank(sortField)) {
            if (order) {
                queryWrapper.orderByAsc(sortField);
            } else {
                queryWrapper.orderByDesc(sortField);
            }
        }
        IPage<AirAlertLog> pageParam = new Page<>(pageNumber, pageSize);
        IPage<AirAlertLog> resultPage = airAlertLogMapper.selectPage(pageParam, queryWrapper);
        return new PageVo<>(resultPage);
    }

    @Override
    public PageVo<AirAlertLog> pageByIcaoCode(Integer pageNumber, Integer pageSize, String icaoCode, String startTime, String endTime, String oderByField, boolean orderByAsc,String keyword, String searchField) throws MyException {
        QueryWrapper<AirAlertLog> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(icaoCode)) {
            queryWrapper.eq("icao_code", icaoCode);
        }
        if (StrUtil.isNotBlank(keyword) && StrUtil.isNotBlank(searchField)) {
            String[]fieldsArray = searchField.split(",");
            for (String field : fieldsArray) {
                queryWrapper.or().like(StrUtil.toUnderlineCase(field), keyword);
            }
        }
        if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) {
            queryWrapper.between("timestamp", startTime, endTime);
        }
        if(StrUtil.isNotBlank(oderByField)){
            if (orderByAsc) {
                queryWrapper.orderByAsc(oderByField);
            } else {
                queryWrapper.orderByDesc(oderByField);
            }
        }
        IPage<AirAlertLog> pageParam = new Page<>(pageNumber, pageSize);
        IPage<AirAlertLog> resultPage = airAlertLogMapper.selectPage(pageParam, queryWrapper);
        return new PageVo<>(resultPage);
    }


}